# frozen_string_literal: true

require_relative '../../../spec_helper'

describe Wpxf::Net::HttpServer do
  let(:requested_file) { '/file.txt' }
  let(:subject) do
    Class.new(Wpxf::Module) do
      include Wpxf::Net::HttpServer
    end.new
  end

  before :each do
    dbl = double('server').as_null_object
    allow(TCPServer).to receive(:new).and_return(dbl)
    allow(dbl).to receive(:gets).and_return(
      "GET #{requested_file} HTTP/1.1\r\n",
      "User-Agent: ExampleBrowser/1.0\r\n",
      "Host: example.com\r\n",
      "Accept: */*\r\n",
      "\r\n"
    )
  end

  describe '#new' do
    it 'registers required options for the server' do
      options = %w(http_server_bind_address http_server_bind_port)
      options.each do |o|
        expect(subject.get_option(o)).to_not be_nil
      end
    end
  end

  describe '#http_server_bind_address' do
    it 'returns the normalized value of the http_server_bind_address option' do
      subject.set_option_value('http_server_bind_address', '127.0.0.1')
      expect(subject.http_server_bind_address).to eq '127.0.0.1'
    end
  end

  describe '#http_server_bind_port' do
    it 'returns the normalized value of the http_server_bind_port option' do
      subject.set_option_value('http_server_bind_port', '8888')
      expect(subject.http_server_bind_port).to eq 8888
    end
  end

  describe '#start_http_server' do
    context 'when a HTTP request is received' do
      it 'calls #on_http_request with the headers parsed into a hash' do
        allow(subject).to receive(:on_http_request) do |_p, _p2, headers|
          expect(headers['User-Agent']).to eq 'ExampleBrowser/1.0'
          expect(headers['Host']).to eq 'example.com'
          expect(headers['Accept']).to eq '*/*'
          subject.stop_http_server
          'res'
        end

        subject.start_http_server
      end

      it 'calls #on_http_request with the path parsed into a string' do
        allow(subject).to receive(:on_http_request) do |path, _p, _h|
          expect(path).to eq '/file.txt'
          subject.stop_http_server
          'res'
        end

        subject.start_http_server
      end

      context 'when the request url has no query string' do
        it 'calls #on_http_request with an empty params arg' do
          allow(subject).to receive(:on_http_request) do |_p, params, _h|
            expect(params).to be_empty
            subject.stop_http_server
            'res'
          end

          subject.start_http_server
        end
      end

      context 'when the request url has a query string' do
        let(:requested_file) { '/file.txt?a=b&c=d' }

        it 'calls #on_http_request with the params parsed into a hash' do
          allow(subject).to receive(:on_http_request) do |_p, params, _h|
            expect(params).to eq('a' => 'b', 'c' => 'd')
            subject.stop_http_server
            'res'
          end

          subject.start_http_server
        end

        it 'calls #on_http_request with the params excluded from the path' do
          allow(subject).to receive(:on_http_request) do |path, _p, _h|
            expect(path).to eq('/file.txt')
            subject.stop_http_server
            'res'
          end

          subject.start_http_server
        end
      end
    end
  end
end
